﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ANZ_AIM_BLL;
using ANZ_AIM_FRAMEWORK;
using ANZ_AIM_BLL.Model;
using ANZ_AIM_GUI.Utils;
using System.Text.RegularExpressions;
using log4net;

namespace ANZ_AIM_GUI
{
    public partial class frmAdminUser : DevComponents.DotNetBar.Office2007Form
    {
        //log4net
        private static readonly ILog logger = LogManager.GetLogger(typeof(frmAdminUser));

        AppParam param = AppParam.Instance;
        public int OpMode { get; set; }
        public User User { get; set; }

        public frmAdminUser()
        {
            InitializeComponent();
            this.InitControls();
        }

        public frmAdminUser(int mode, User user)
            : this()
        {
            try
            {
                this.OpMode = mode;
                this.User = user;
                LoadRoleList();
                switch (OpMode)
                {
                    case MiscHelper.FORM_OPMODE_ADD_NEW:
                        this.Text = "Add User";
                        this.chbActive.Checked = false;
                        this.dtpCreateDate.Value = DateTime.Now;
                        break;
                    case MiscHelper.FORM_OPMODE_EDIT:
                        this.Text = "Edit User";
                        cmdAdd.Text = "UPDATE";
                        lblHeader.Text = "User management - Edit user";
                        this.txtUsername.ReadOnly = true;
                        this.UnpackObject();
                        break;
                    default:
                        break;
                }
                this.InitControls();
            }
            catch (Exception ex) { throw ex; }
        }

        private void InitControls()
        {
            try
            {
                this.txtUsername.MaxLength = 50;
                this.txtFullname.MaxLength = 50;
                this.txtEmail.MaxLength = 50;
            }
            catch (Exception ex) { throw ex; }
        }

        private void LoadRoleList()
        {
            try
            {
                // load Role combo
                ((ListBox)cblRole).DataSource = null;

                RoleBLL roleBll = new RoleBLL();
                DataTable dataTableRole = roleBll.GetRoles();

                if (OpMode == MiscHelper.FORM_OPMODE_ADD_NEW || (OpMode == MiscHelper.FORM_OPMODE_EDIT && !User.Role.Contains(User.ROLE_ADMIN)))
                {
                    dataTableRole.Rows.RemoveAt(4);
                }

                ((ListBox)cblRole).DataSource = dataTableRole;
                ((ListBox)cblRole).DisplayMember = "RoleName";
                ((ListBox)cblRole).ValueMember = "RoleID";
            }
            catch (Exception ex) { throw ex; }
        }

        private void UnpackObject()
        {
            try
            {
                this.txtUsername.Text = User.UserName;
                this.txtFullname.Text = User.FullName;
                this.txtEmail.Text = User.Email;
                if (User.Role.Contains(User.ROLE_ADMIN))
                {
                    chbActive.Enabled = false;
                    cblRole.Enabled = true; //08Jan2015 Change to true to enable admin edit role himself
                }
                this.chbActive.Checked = User.IsActive;
                this.dtpCreateDate.Value = Convert.ToDateTime(User.CreatedDate);
                this.dtpCreateDate.Enabled = false;
                BindRoleList(User.Role);
            }
            catch (Exception ex) { throw ex; }
        }

        private void PackObject()
        {
            try
            {
                User.UserName = this.txtUsername.Text;
                User.FullName = this.txtFullname.Text;
                User.Email = this.txtEmail.Text;
                string role = "";
                for (int i = 0; i < cblRole.Items.Count; i++)
                {
                    if (cblRole.GetItemChecked(i))
                    {
                        role += cblRole.GetItemText(cblRole.Items[i]) + ",";
                    }
                }
                User.Role = role.Remove(role.Length - 1, 1);
                User.IsActive = this.chbActive.Checked;
            }
            catch (Exception ex) { throw ex; }
        }

        private void BindRoleList(string role)
        {
            try
            {
                string[] listRole = role.Split(',');
                for (int i = 0; i < cblRole.Items.Count; i++)
                {
                    foreach (string s in listRole)
                    {
                        if (cblRole.GetItemText(cblRole.Items[i]).Equals(s))
                        {
                            cblRole.SetItemChecked(i, true);

                            //08Jan2015 Disable Admin role
                            if (cblRole.GetItemText(cblRole.Items[i]).Equals(User.ROLE_ADMIN))
                            {
                                cblRole.SetItemCheckState(i, CheckState.Indeterminate);
                            }
                        }
                    }
                }
            }
            catch (Exception ex) { throw ex; }
        }

        private void cmdCancel_Click(object sender, EventArgs e)
        {
            try
            {
                Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.InnerException == null ? ex.Message : ex.InnerException.Message, Constant.SYS_ERROR, MessageBoxButtons.OK);
                logger.Error(ex.Message + " - " + ex.StackTrace);
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            try
            {
                clearClick();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.InnerException == null ? ex.Message : ex.InnerException.Message, Constant.SYS_ERROR, MessageBoxButtons.OK);
                logger.Error(ex.Message + " - " + ex.StackTrace);
            }
        }

        private void cmdAdd_Click(object sender, EventArgs e)
        {
            var msg = String.Empty;
            try
            {
                if (!this.validateForm())
                    return;

                this.PackObject();
                this.User.LastUpdatedBy = param.UserName;
                this.User.LastUpdatedDate = MiscHelper.DateTimeToShort(DateTime.Now);
                switch (OpMode)
                {
                    case MiscHelper.FORM_OPMODE_ADD_NEW:
                        msg = Constant.SYS_MSG_ADD_USER;
                        string newPwds = MiscHelper.GetRandomString();
                        this.User.Password = newPwds; // param.DefaultPassword;
                        this.User.CreatedBy = param.UserName;
                        this.User.CreatedDate = MiscHelper.DateTimeToShort(DateTime.Now);
                        this.User.MustChangePwd = "Y";
                        this.User.IsLock = false;
                        AddUser();
                        //MessageBox.Show("New user added." + System.Environment.NewLine + "Password: " + newPwds, Constant.SYS_INFORMATION, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        frmPassword fmPwd = new frmPassword(newPwds, "New user added.");
                        fmPwd.ShowDialog();
                        this.Dispose();
                        break;
                    case MiscHelper.FORM_OPMODE_EDIT:
                        msg = Constant.SYS_MSG_EDIT_USER;
                        EditUser();
                        MessageBox.Show("User saved.", Constant.SYS_INFORMATION, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        this.Dispose();
                        break;
                    default:
                        return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.InnerException == null ? ex.Message : ex.InnerException.Message, Constant.SYS_ERROR, MessageBoxButtons.OK);
                logger.Error(ex.Message + " - " + ex.StackTrace);
                return;
            }

            try
            {
                if (!String.IsNullOrEmpty(msg))
                {
                    LogBLL logBll = new LogBLL();
                    logBll.Description = msg;
                    logBll.Log(this.FindForm(), param.UserName);
                }
            }
            catch { }
        }

        private bool validateForm()
        {
            try
            {
                this.errUser.Clear();
                bool result = true;

                if (this.txtUsername.Text == "")
                {
                    result = false;
                    this.errUser.SetError(this.txtUsername, "User Name cannot be empty.");
                    return result;
                }
                else
                {
                    //08Jan2015 Check user name policy
                    if (this.OpMode == MiscHelper.FORM_OPMODE_ADD_NEW)
                    {
                        //if (!System.Text.RegularExpressions.Regex.IsMatch(this.txtUsername.Text, "[a-z0-9]", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
                        if (this.txtUsername.Text != new string(this.txtUsername.Text.Where(c => Char.IsLetterOrDigit(c) || Char.IsWhiteSpace(c)).ToArray())
                            || this.txtUsername.Text.Length < 6
                            || this.txtUsername.Text.Contains(" ")
                            )
                        {
                            result = false;
                            this.errUser.SetError(this.txtUsername, "Username must be at least 6 characters and not contain space, special chars");
                        }
                    }

                    if (this.OpMode == MiscHelper.FORM_OPMODE_ADD_NEW)
                    {
                        string tmp = this.CheckUser(this.txtUsername.Text);
                        if (tmp != null)
                        {
                            result = false;
                            this.errUser.SetError(this.txtUsername, "The username is existed, please input another username.");
                        }
                    }
                }
                if (this.txtFullname.Text == "")
                {
                    result = false;
                    this.errUser.SetError(this.txtFullname, "Please input this field.");
                    return result;
                }
                if (this.txtEmail.Text == "")
                {
                    result = false;
                    this.errUser.SetError(this.txtEmail, "Please input this field.");
                    return result;
                }
                else
                {
                    if (!IsEmail(txtEmail.Text.Trim()))
                    {
                        result = false;
                        this.errUser.SetError(this.txtEmail, "The Email format is incorrect, please input again.");
                        return result;
                    }
                }

                if (this.cblRole.CheckedItems.Count == 0)
                {
                    result = false;
                    this.errUser.SetError(this.cblRole, "Please input this field");
                    return result;
                }
                else
                {
                    //08Jan2015 Enable Admin to edit role himself but cannot remove Amin role
                    if (OpMode == MiscHelper.FORM_OPMODE_EDIT)
                    {
                        if (User.Role.Contains(User.ROLE_ADMIN))
                        {
                            string role = "";
                            for (int i = 0; i < cblRole.Items.Count; i++)
                            {
                                if (cblRole.GetItemChecked(i))
                                {
                                    role += cblRole.GetItemText(cblRole.Items[i]) + ",";
                                }
                            }

                            if (!role.Contains(User.ROLE_ADMIN))
                            {
                                result = false;
                                this.errUser.SetError(this.cblRole, "Role Admin cannot be unchecked");
                            }
                        }
                    }
                }

                return result;
            }
            catch (Exception ex) { throw ex; }
        }

        public void AddUser()
        {
            try
            {
                UserBLL userBll = new UserBLL();

                // encrypt password
                string plainPassword = User.Password;
                AESHelper aes = new AESHelper();
                User.Password = aes.EncryptToString(plainPassword);

                userBll.Save(User);
            }
            catch (Exception ex) { throw ex; }
        }

        public void EditUser()
        {
            try
            {
                UserBLL userBll = new UserBLL();
                userBll.Save(User);
            }
            catch (Exception ex) { throw ex; }
        }

        public string CheckUser(string userName)
        {
            try
            {
                UserBLL userBll = new UserBLL();
                User tmp = userBll.GetByUsername(userName);
                if (tmp != null)
                    return tmp.UserName;
                else
                    return null;
            }
            catch (Exception ex) { throw ex; }
        }

        private bool IsEmail(string email)
        {
            try
            {
                bool result = false;

                /* Regular expression pattern for a strong password:
                 * - Has at least 8 characters
                 * - Has at least 1 alpha character
                 * - Has at least 1 numeric character
                 * - Has at least 1 capital letter
                 * - Has no special character
                 * Source: http://stackoverflow.com/questions/3131025/strong-password-regex
                 */
                string pattern = @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";

                if (Regex.IsMatch(email, pattern, RegexOptions.IgnoreCase))
                    result = true;

                return result;
            }
            catch (Exception ex) { throw ex; }
        }

        private void checkRoleAdmin()
        {
            try
            {
                if (OpMode == MiscHelper.FORM_OPMODE_ADD_NEW)
                {
                    cblRole.SetItemCheckState(0, CheckState.Unchecked);
                }
            }
            catch (Exception ex) { throw ex; }
        }

        private void clearClick()
        {
            try
            {
                switch (OpMode)
                {
                    case MiscHelper.FORM_OPMODE_ADD_NEW:
                        txtUsername.Text = "";
                        txtFullname.Text = "";
                        txtEmail.Text = "";
                        chbActive.Checked = false;
                        LoadRoleList();
                        break;
                    case MiscHelper.FORM_OPMODE_EDIT:
                        txtFullname.Text = "";
                        txtEmail.Text = "";
                        chbActive.Checked = false;
                        //LoadRoleList(); //09Jan2015
                        cblRole_ClearChecked();
                        dtpCreateDate.Value = DateTime.Now;
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex) { throw ex; }
        }

        private void cblRole_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            try
            {
                if (e.CurrentValue == CheckState.Indeterminate)
                {
                    e.NewValue = CheckState.Indeterminate;
                }
            }
            catch (Exception ex) { throw ex; }
        }

        private void cblRole_ClearChecked()
        {
            try
            {
                for (int i = 0; i < cblRole.Items.Count; i++)
                {
                    //08Jan2015 Disable Admin role
                    if (!cblRole.GetItemText(cblRole.Items[i]).Equals(User.ROLE_ADMIN))
                    {
                        cblRole.SetItemCheckState(i, CheckState.Unchecked);
                    }
                }
            }
            catch (Exception ex) { throw ex; }
        }
    }
}
